package libs;

import java.util.*;
import java.text.*;
import java.awt.Image;
import java.awt.image.PixelGrabber;

public class Moments {
    double mean = 0.0;
    double min=0.0;
    double max=0.0;
    double average_deviation = 0.0;
    double standard_deviation = 0.0;
    double variance = 0.0;
    double skewness = 0.0;
    double kurtosis = 0.0;
    double inv_diff_moments=0.0;
    double contrast=0.0;
    double entropy=0.0;
    double energy=0.0;
    
    private double deviation = 0.0;
	
//********** get methods **********************
    public double getMin(Vector data){
    	Object obj=Collections.min(data);
    	return Double.parseDouble(obj.toString());
    }
    
    public double getMax(Vector data){
    	Object obj=Collections.max(data);
    	return Double.parseDouble(obj.toString());
    }
    
    public double getMean(){
    	return this.mean;
    }
    
    public double getAverageDeviation(){
    	return this.average_deviation;
    }
    
    public double getStandardDeviation(){
    	return this.standard_deviation;
    }
    
    public double getVariance(){
    	return this.variance;
    }
    
    public double getSkewness(){
    	return this.skewness;
    }
    
    public double getKurtosis(){
    	return this.kurtosis;
    }
    
    public double getInvDiffMoment(){
    	return this.inv_diff_moments;
    }
    
    public double getContrast(){
    	return this.contrast;
    }
    
    public double getEntropy(){
    	return this.entropy;
    }
    
    public double getEnergy(){
    	return this.energy;
    }
 
    
//*********************************************************************************    
    
    
	public double addThem(Vector data){
		double ret=0;
		
		for (int i = 0; i < data.size(); i++) {
			double x=Double.parseDouble(data.get(i).toString());
			ret+=x;
		}
		return Utils.formatDouble(ret);
	}
	
	public String getMeanFeatures(Image imgx) {
		NumberFormat nf = NumberFormat.getInstance();
		nf.setMaximumFractionDigits(3);
		nf.setGroupingUsed(false);
		Vector<String> nums=imageToPixelsVector(imgx);
		int n = nums.size();
		String ret="";
		mean=0;
		deviation=0;
		variance=0;
		standard_deviation=0;
		mean = addThem(nums) / n;
		ret=nf.format(mean)+";";			
		return ret;
	}
	
	public String getMeanFeaturesWithExposureNormalized(int n,String type,Image imgx,String flag) {
		int[][] data=ImageProcess.imageToPixels255(imgx);
		if (type.equals("halogen")) {
			if(n>=0 && n<=9){
				//bu bolgeyi exposure suresine gore normalize etme diger bolgeleri et.
			}else if(n>9 && n<=19){
				data=ImageProcess.normalizeArrayWithExposure(4.5/2.4,data);			
			}else{
				data=ImageProcess.normalizeArrayWithExposure(4.5/0.5,data);
			}
			
		}else{ //eger modality uv ise
			if(n>=0 && n<=29){
				//bu bolgeyi exposure suresine gore normalize etme diger bolgeleri et.
			}else{
				data=ImageProcess.normalizeArrayWithExposure(9.6/3.1,data);
			}
			
		}
		double mean=Utils.getMean(data);
		return mean+";";
	}

	public String findAllMoments(Image imgx,String type,int region){
		String ret="";
		int[][] data=ImageProcess.imageToPixels255(imgx);
		if (type.equals("halogen")) {
			if(region>=0 && region<=9){
				//bu bolgeyi exposure suresine gore normalize etme diger bolgeleri et.
			}else if(region>9 && region<=19){
				data=ImageProcess.normalizeArrayWithExposure(4.5/2.4,data);			
			}else{
				data=ImageProcess.normalizeArrayWithExposure(4.5/0.5,data);
			}			
		}else{ //eger modality uv ise
			if(region>=0 && region<=29){
				//bu bolgeyi exposure suresine gore normalize etme diger bolgeleri et.
			}else{
				data=ImageProcess.normalizeArrayWithExposure(9.6/3.1,data);
			}
			
		}
		
		int col=data.length;
		int row=data[0].length;
		//yaz("row:"+row);
		//yaz("col:"+col);
		reset_allMoments();
		for (int i = 0; i < col; i++) {
			for (int j = 0; j < row; j++) {
				inv_diff_moments+=data[i][j]/(1+(i-j)*(i-j));
				contrast+=data[i][j]*((i-j)*(i-j));
				entropy+=data[i][j]*Math.log(data[i][j]+1);
				energy+=data[i][j]*data[i][j];
			}
		}
		Vector nums=imageToPixelsVector(imgx);
		int n = nums.size();
		//mean = addThem(nums) / n;
		mean=Utils.getMean(data);
		for (int i = 0; i < n; i++) {
			deviation = ((Double) nums.get(i)).doubleValue() - mean;
			average_deviation += Math.abs(deviation);
			variance += Math.pow(deviation, 2);
			skewness += Math.pow(deviation, 3);
			kurtosis += Math.pow(deviation, 4);
		}
		average_deviation /= n;
		variance = variance / n;
		standard_deviation = Math.sqrt(variance);
		if (variance != 0.0) {
			skewness /= (n * variance * standard_deviation);
			kurtosis = kurtosis / (n * variance * variance);
		}
		min=findMin(nums);
		max=findMax(nums);
		NumberFormat nf = NumberFormat.getInstance();
		nf.setMaximumFractionDigits(13);
		nf.setGroupingUsed(false);
		nf.setMaximumFractionDigits(6);
		nf.setMinimumFractionDigits(6);
		
		ret=Utils.formatDouble(mean)+";"+
			Utils.formatDouble(standard_deviation)+";"+
			Utils.formatDouble(variance)+";"+
			Utils.formatDouble(skewness)+";"+
			Utils.formatDouble(kurtosis)+";"+
			Utils.formatDouble(inv_diff_moments)+";"+
			Utils.formatDouble(contrast)+";"+
			Utils.formatDouble(entropy)+";"+
			Utils.formatDouble(energy)+";";
		
		
//		System.out.println("from AllMoments");	
//		System.out.println("mean:               " + nf.format(mean));
//		System.out.println("average_deviation:  " + nf.format(average_deviation));
//		System.out.println("standard_deviation: " + nf.format(standard_deviation));
//		System.out.println("variance:           " + nf.format(variance));
//		System.out.println("skew:               " + nf.format(skewness));
//		System.out.println("kurtosis:           " + nf.format(kurtosis));
		return ret;
	}
	
	private double findMax(Vector nums) {
		double max=(Double)nums.get(0);
		for (int i = 0; i < nums.size(); i++) {
			if (max<(Double)nums.get(i)) {
				max=(Double)nums.get(i);
			}
		}
		return max;
	}

	private double findMin(Vector nums) {
		double min=(Double)nums.get(0);
		for (int i = 0; i < nums.size(); i++) {
			if (min>(Double)nums.get(i)) {
				min=(Double)nums.get(i);
			}
		}
		return min;
	}

	private void reset_allMoments() {
		// TODO Auto-generated method stub
	    mean = 0.0;
	    min=0.0;
	    max=0.0;
	    average_deviation = 0.0;
	    standard_deviation = 0.0;
	    variance = 0.0;
	    skewness = 0.0;
	    kurtosis = 0.0;
	    inv_diff_moments=0.0;
	    contrast=0.0;
	    entropy=0.0;
	    energy=0.0;		
	}

	public double findInverseDiffMoment(int[][] img){
		int col=img.length;
		int row=img[0].length;
		double IDF=0.0d;
		for (int i = 0; i < row; i++) {
			for (int j = 0; j < col; j++) {
				IDF+=img[i][j]/(1+(i-j)*(i-j));
			}
		}
		return IDF;
	}
	
	public double findContrast(int[][] img){
		int col=img.length;
		int row=img[0].length;
		double contrast=0.0d;
		for (int i = 0; i < row; i++) {
			for (int j = 0; j < col; j++) {
				contrast+=img[i][j]*((i-j)*(i-j));
			}
		}
		return contrast;
	}
	
	public double findEntropy(int[][] img){
		int col=img.length;
		int row=img[0].length;
		double entropy=0.0d;
		for (int i = 0; i < row; i++) {
			for (int j = 0; j < col; j++) {
				entropy+=img[i][j]*Math.log(img[i][j]);
			}
		}
		return entropy;
	}
	
	public double findEnergy(int[][] img){
		int col=img.length;
		int row=img[0].length;
		double energy=0.0d;
		for (int i = 0; i < row; i++) {
			for (int j = 0; j < col; j++) {
				energy+=img[i][j]*img[i][j];
			}
		}
		return energy;
	}

	private  int[][] imageToPixels2D(Image img){
//        MediaTracker mt = new MediaTracker(null);
//        mt.addImage(img, 0);
//        try {
//            mt.waitForID(0);
//        } catch (Exception e) {
//    		// TODO: handle exception
//    	}
        
        int w = img.getWidth(null);
        int h = img.getHeight(null);
        //System.out.println("w:"+w+" h:"+h);
        int pixels[] = new int[w * h];
        int fpixels[] = new int[w * h];
        int dpixel[][] = new int[w][h];
        PixelGrabber pg = new PixelGrabber(img, 0, 0, w, h, pixels, 0, w);
        try {
            pg.grabPixels();
    	} catch (Exception e) {
    		// TODO: handle exception
    	}
      	
    	for(int i = 0; i < pixels.length; i++)
        {
            int r = pixels[i] >> 16 & 0xff;
            int g = pixels[i] >> 8 & 0xff;
            int b = pixels[i] >> 0 & 0xff;
            int y = (int)(0.33000000000000002D * (double)r + 0.56000000000000005D * (double)g + 0.11D * (double)b);
            fpixels[i]=y;
        }
        
    	int k=0;
    	for (int i = 0; i < h; i++) {
			for (int j = 0; j < w; j++) {
				dpixel[j][i]=fpixels[k];
				k++;
			}
		}
		return dpixel;
	}
	
	private  int[] imageToPixels1D(Image img){
//      MediaTracker mt = new MediaTracker(null);
//      mt.addImage(img, 0);
//      try {
//          mt.waitForID(0);
//      } catch (Exception e) {
//  		// TODO: handle exception
//  	}
//      
        int w = img.getWidth(null);
		int h = img.getHeight(null);
		// System.out.println("w:"+w+" h:"+h);
		int pixels[] = new int[w * h];
		int fpixels[] = new int[w * h];
		int dpixel[][] = new int[w][h];
		PixelGrabber pg = new PixelGrabber(img, 0, 0, w, h, pixels, 0, w);
		try {
			pg.grabPixels();
		} catch (Exception e) {
			// TODO: handle exception
		}

		for (int i = 0; i < pixels.length; i++) {
			int r = pixels[i] >> 16 & 0xff;
			int g = pixels[i] >> 8 & 0xff;
			int b = pixels[i] >> 0 & 0xff;
			int y = (int) (0.33000000000000002D * (double) r
					+ 0.56000000000000005D * (double) g + 0.11D * (double) b);
			fpixels[i] = y;
		}

		int k = 0;
		return fpixels;
	}
	
	private  Vector imageToPixelsVector(Image img){
	  Vector ret=new Vector();
      int w = img.getWidth(null);
      int h = img.getHeight(null);
      //System.out.println("w:"+w+" h:"+h);
      int pixels[] = new int[w * h];
      int fpixels[] = new int[w * h];
      PixelGrabber pg = new PixelGrabber(img, 0, 0, w, h, pixels, 0, w);
      try {
			pg.grabPixels();
	  } catch (Exception e) {
			// TODO: handle exception
	  }
	  
	  for (int i = 0; i < pixels.length; i++) {
			int r = pixels[i] >> 16 & 0xff;
			int g = pixels[i] >> 8 & 0xff;
			int b = pixels[i] >> 0 & 0xff;
			int y = (int) (0.33000000000000002D * (double) r
					+ 0.56000000000000005D * (double) g + 0.11D * (double) b);
			fpixels[i] = y;
			ret.add(y*1.0d);
	  }
	  return ret;

	}
	
	public double findKurtosis(Image imgx){
		return findKurtosis(imageToPixelsVector(imgx));
	}
	
	public double findKurtosis(Vector nums){
		int n = nums.size();
		double sum=addThem(nums);
		double mean = sum / n;
		double deviation=0.0d;
		double variance=0.0d;
		double k=0.0d;
		
		for (int i = 0; i < n; i++) {
			deviation = ((Double) nums.get(i)).doubleValue() - mean;
			variance += Math.pow(deviation, 2);
			k += Math.pow(deviation, 4);
		}
		//variance /= (n - 1);
		variance=variance/n;
		if (variance != 0.0) {
			//k = k / (n * variance * variance) - 3.0;
			k = k / (n*variance * variance);
		}
		return k;
	}


	public double findSkewness(Image imgx){
		return findSkewness(imageToPixelsVector(imgx));
	}
	
	public double findSkewness(Vector nums){
		int n = nums.size();
		double sum=addThem(nums);
		double mean = sum / n;
		double deviation=0.0d;
		double standard_deviation=0.0d;
		double variance=0.0d;
		double skew=0.0d;
		
		for (int i = 0; i < n; i++) {
			deviation = ((Double) nums.get(i)).doubleValue() - mean;
			variance += Math.pow(deviation, 2);
			skew += Math.pow(deviation, 3);
		}
		//variance /= (n - 1);
		variance /= n;
		standard_deviation = Math.sqrt(variance);
		if (variance != 0.0) {
			skew /= (n * variance * standard_deviation);
		}
		return skew;
	}
	

	public double findVariance(Image imgx){
		return findVariance(imageToPixelsVector(imgx));
	}
	

	public double findVariance(Vector nums){
		int n = nums.size();
		double sum=addThem(nums);
		double mean = sum / n;
		double deviation=0.0d;
		double varyans=0.0d;
		for (int i = 0; i < n; i++) {
			deviation = ((Double) nums.get(i)).doubleValue() - mean;
			varyans += Math.pow(deviation, 2);
		}
		varyans /= (n - 1);
		return varyans;
	}
	

	public double findStdDeviation(Image imgx){
		return findStdDeviation(imageToPixelsVector(imgx));
	}
	
	public double findStdDeviation(Vector<String> nums){
		int n = nums.size();
		double sum=addThem(nums);
		double mean = sum / n;
		double deviation=0.0d;
		double standard_deviation=0.0d;
		double variance=0.0d;
		
		for (int i = 0; i < n; i++) {
			deviation = Double.parseDouble(nums.get(i)) - mean;
			variance += Math.pow(deviation, 2);
		}
		variance /= (n - 1);
		standard_deviation = Math.sqrt(variance);
		if (standard_deviation<0.00001) {
			standard_deviation=0.0;
		}
		return standard_deviation;
	}
	

	public double findAverageDeviation(Image imgx){
		return findAverageDeviation(imageToPixelsVector(imgx));
	}		
	
	public double findAverageDeviation(Vector nums){
		int n = nums.size();
		double sum=addThem(nums);
		double mean = sum / n;
		double deviation=0.0d;
		double average_deviation=0.0d;
		
		for (int i = 0; i < n; i++) {
			deviation = ((Double) nums.get(i)).doubleValue() - mean;
			average_deviation += Math.abs(deviation);
		}
		average_deviation /= n;
		return average_deviation;
	}
	

	public double findMean(Image imgx){
		return findMean(imageToPixelsVector(imgx));
	}		
	
	public double findMean(Vector nums){
		int n = nums.size();
		double sum=addThem(nums);
		double mean = sum / n;
		return mean;
	}
	
	public static double getMean(double[] p){
		double toplam=0;
		for (int i = 0; i < p.length; i++) {
			toplam+=p[i];
		}
		return toplam/p.length;
	}
	
	public static double getStandardDeviation(double[] p){
		double mean = getMean(p);
		double deviation=0.0d;
		double standard_deviation=0.0d;
		double variance=0.0d;
		
		for (int i = 0; i < p.length; i++) {
			deviation = p[i] - mean;
			variance += Math.pow(deviation, 2);
		}
		variance /= (p.length - 1);
		return standard_deviation = Math.sqrt(variance);
	}
	
	public double findMagnitude(Vector<String> nums){
		int n = nums.size();
		double ret=0;
		for (int i = 0; i < n; i++) {
//			double temp=((Double) nums.get(i)).doubleValue();
			double temp=Double.parseDouble(nums.get(i));
			ret+=temp*temp;
		}
		return Math.sqrt(ret);
	}
	

	
	

public static void main(String[] args) {
    String line;
    Vector nums = new Vector();
    double mean = 0.0;
    double average_deviation = 0.0;
    double standard_deviation = 0.0;
    double variance = 0.0;
    double skew = 0.0;
    double kurtosis = 0.0;
    double num, sum = 0.0;
    double median = 0.0;
    double deviation = 0.0;
    int i, n, mid = 0;
    
    //System.out.println("log(100)"+Math.log(1000));

    
//	for (int j = 0; j < 100; j++) {
//		num=Math.round(Math.random()*10);
//		System.out.println("num:"+num);
//		sum+=num;
//		nums.add(new Double(num));
//	}
//    1     3     7     2     9    11    16
    sum+=1.0;
    nums.add(1.0);
    
    sum+=3.0;
    nums.add(3.0);
    
    sum+=7.0;
    nums.add(7.0);
    
    sum+=2.0;
    nums.add(2.0);
    
    sum+=9.0;
    nums.add(9.0);
    
    sum+=11.0;
    nums.add(11.0);
    
    sum+=16.0;
    nums.add(16.0);

	n = nums.size();
	mean = sum / n;
	for (i = 0; i < n; i++) {
		deviation = ((Double) nums.get(i)).doubleValue() - mean;
		average_deviation += Math.abs(deviation);
		variance += Math.pow(deviation, 2);
		skew += Math.pow(deviation, 3);
		kurtosis += Math.pow(deviation, 4);
	}
	average_deviation /= n;
	variance /= (n - 1);
	standard_deviation = Math.sqrt(variance);
	if (variance != 0.0) {
		skew /= (n * variance * standard_deviation);
		kurtosis = kurtosis / (n * variance * variance) - 3.0;
	}

	Collections.sort(nums);


	mid = (n / 2);
	median = (n % 2 != 0) ? ((Double) nums.get(mid)).doubleValue()
			: (((Double) nums.get(mid)).doubleValue() + ((Double) nums.get(mid - 1)).doubleValue()) / 2;

	NumberFormat nf = NumberFormat.getInstance();
	nf.setMaximumFractionDigits(13);
	nf.setGroupingUsed(false);
	nf.setMaximumFractionDigits(6);
	nf.setMinimumFractionDigits(6);

	System.out.println("n:                  " + n);
	System.out.println("median:             " + nf.format(median));
	System.out.println("mean:               " + nf.format(mean));
	System.out.println("average_deviation:  " + nf.format(average_deviation));
	System.out.println("standard_deviation: " + nf.format(standard_deviation));
	System.out.println("variance:           " + nf.format(variance));
	System.out.println("skew:               " + nf.format(skew));
	System.out.println("kurtosis:           " + nf.format(kurtosis));
	
	Moments m=new Moments();
	System.out.println("from methods");	
	System.out.println("mean:               " + nf.format(m.findMean(nums)));
	System.out.println("average_deviation:  " + nf.format(m.findAverageDeviation(nums)));
	System.out.println("standard_deviation: " + nf.format(m.findStdDeviation(nums)));
	System.out.println("variance:           " + nf.format(m.findVariance(nums)));
	System.out.println("skew:               " + nf.format(m.findSkewness(nums)));
	System.out.println("kurtosis:           " + nf.format(m.findKurtosis(nums)));
	//m.findAllMoments(imgx)
}


}